             package com.java.diagnostics.visualizer.gc.realtimeV2.parser;
             
             import com.java.diagnostics.visualizer.data.SourceData;
             import com.java.diagnostics.visualizer.data.StructuredDataBuilder;
             import com.java.diagnostics.visualizer.data.TupleDataBuilder;
             import com.java.diagnostics.visualizer.data.axes.Axis;
             import com.java.diagnostics.visualizer.data.axes.AxisPair;
             import com.java.diagnostics.visualizer.data.axes.XDataAxis;
             import com.java.diagnostics.visualizer.data.axes.YDataAxis;
             import com.java.diagnostics.visualizer.exceptions.GCAndMemoryVisualizerException;
             import com.java.diagnostics.visualizer.exceptions.GCAndMemoryVisualizerParsedDataCorruptedException;
             import com.java.diagnostics.visualizer.factory.DataFactory;
             import com.java.diagnostics.visualizer.factory.SourceDataFactory;
             import com.java.diagnostics.visualizer.gc.realtime.parser.RTXMLParser;
             import com.java.diagnostics.visualizer.gc.realtime.util.Messages;
             import com.java.diagnostics.visualizer.metadata.TupleMetaData;
             import com.java.diagnostics.visualizer.metadata.TupleMetaData.TableField;
             import com.java.diagnostics.visualizer.metadata.TupleMetaData.TableType;
             import com.java.diagnostics.visualizer.parser.vgc.constants.VGCAxes;
             import com.java.diagnostics.visualizer.parser.vgc.converters.EventUnitConverter;
             import com.java.diagnostics.visualizer.parser.vgc.converters.GCNumberConverter;
             import com.java.diagnostics.visualizer.parser.vgc.j9.FriendlyXMLParser;
             import com.java.diagnostics.visualizer.properties.OutputProperties;
             import com.java.diagnostics.visualizer.sources.Source;
             import java.io.IOException;
             import java.text.MessageFormat;
             import javax.xml.parsers.ParserConfigurationException;
             import org.xml.sax.Attributes;
             import org.xml.sax.SAXException;
             import org.xml.sax.SAXParseException;
             
             public class BaseParser
               extends RTXMLParser
             {
               static final String TIMESTAMP = "timestamp";
               static final String VERBOSEGC = "verbosegc";
               static final String INITIALIZED = "initialized";
               static final String EVENT = "event";
               static final String GC = "gc";
               static final String REALTIMEVGC_CONTENT_TYPE = "realtimevgc";
               static final String TYPE = "type";
               static final String HEAPFREEBYTES = "heapfreebytes";
               static final String INTERVALMS = "intervalms";
               static final String ID = "id";
               private TimeManager timeManager;
               private IntervalManager intervalManager;
               private CommonData commonData;
               private Source source;
               private EventUnitConverter eventConverter = new EventUnitConverter();
               
               private GCEventHandler eventHandler;
               
               private TupleDataBuilder triggerDurations;
               
               private TupleDataBuilder cycleDurations;
               
               private TupleDataBuilder quantaPerCycle;
               
               private long cycleCount;
               private boolean hasSynchGC;
               private boolean initialized;
               private HeartBeatParser heartbeatParser;
               private SynchGCParser synchGCParser;
               private AttributeParser attributeParser;
               private Parser currentParser;
               
               public SourceData parse(Source source, OutputProperties properties)
                 throws GCAndMemoryVisualizerException
               {
                 this.source = source;
                 this.properties = properties;
                 initialisePreferences();
                 this.isGoodData = false;
                 
                 String variantIdentifier = source.getVariantIdentifier();
                 this.sourceData = 
                   GCANDMEMORYVISUALIZER_SOURCE_DATA_FACTORY.createSourceData(variantIdentifier);
                 try {
                   FriendlyXMLParser parser = new FriendlyXMLParser();
                   parser.parse(source, this);
                 }
                 catch (SAXParseException e)
                 {
                   if (e.getMessage().indexOf("[xX][mM][lL]") > -1) {
                     throw new GCAndMemoryVisualizerParsedDataCorruptedException(
                       CONCATENATED_XML_MESSAGE, e.getLineNumber(), 
                       e.getColumnNumber(), source.getName());
                   }
                   throw new GCAndMemoryVisualizerParsedDataCorruptedException(
                     MessageFormat.format(BADLY_FORMED_XML_MESSAGE, 
                     new Object[] { e.getMessage() }), e
                     .getLineNumber(), e.getColumnNumber(), 
                     source.getName());
                 }
                 catch (SAXException se) {
                   throw new GCAndMemoryVisualizerException(se);
                 }
                 catch (ParserConfigurationException pe) {
                   throw new GCAndMemoryVisualizerException(pe);
                 }
                 catch (IOException ioe) {
                   throw new GCAndMemoryVisualizerException(ioe);
                 }
                 catch (Exception e) {
                   throw new GCAndMemoryVisualizerException(e);
                 }
                 if (this.isGoodData) {
                   source.addSpecificContentType("realtimevgc");
                   source.addGeneralContentType("xml");
                   this.xAxis.updateNormalisation(this.sourceData);
                 }
                 return this.sourceData;
               }
               
               public void startElement(String uri, String localName, String name, Attributes atts)
               {
                 if (this.currentParser != null) {
                   if (this.currentParser.startElement(uri, localName, name, atts, 
                     this.currentComment)) {
                     return;
                   }
                   this.currentParser = null;
                 }
                 
                 if (name.equals("gc")) {
                   initialize();
                   String type = atts.getValue("type");
                   if (type == null) {
                     return;
                   }
                   String millisString = atts.getValue("intervalms");
                   double intervalMillis = 
                     CommonData.convertPositiveDouble(millisString);
                   if (intervalMillis < 0.0D) {
                     return;
                   }
                   double intervalMicros = (intervalMillis * 1000.0D);
                   long id = CommonData.convertPositiveInteger(atts.getValue("id"));
                   this.currentComment = 
                     COMBINED_COMMENT.format(new Object[] { name, type });
                   boolean isHeartBeat = type.equals("heartbeat");
                   if ((isHeartBeat) || (type.equals("synchgc"))) {
                     long timeMicros;
                     GCEventParser currentGCEventParser;
                     if (isHeartBeat) {
                        timeMicros = this.intervalManager
                         .getTimeForHeartbeat((long) intervalMicros);
                       
                       if ((this.cycleCount > 0L) && 
                         (timeMicros < this.intervalManager.lastCycleStart)) {
                         timeMicros = this.intervalManager.lastHeartbeat = this.intervalManager.lastCycleStart;
                       }
                       
                        currentGCEventParser = this.heartbeatParser;
                       
                       long newTimeMicros = this.timeManager.getTimeVal(atts, 
                         timeMicros);
                       if (newTimeMicros != timeMicros) {
                         this.intervalManager.lastHeartbeat = (timeMicros = newTimeMicros);
                       }
                     }
                     else {
                       this.hasSynchGC = true;
                       timeMicros = this.intervalManager
                         .getTimeForSynchGC((long) intervalMicros);
                       currentGCEventParser = this.synchGCParser;
                       
                       long newTimeMicros = this.timeManager.getTimeVal(atts, 
                         timeMicros);
                       if (newTimeMicros != timeMicros) {
                         this.intervalManager.lastSynchGC = (timeMicros = newTimeMicros);
                       }
                     }
                     currentGCEventParser.init(timeMicros, this.currentComment, 
(long)                        intervalMicros);
                     this.currentParser = currentGCEventParser;
                     currentGCEventParser.id = id;
                   }
                   else
                   {
                     boolean isTriggerEnd = type.equals("trigger end");
                     boolean isCycleEnd; 
                     boolean isCycleStart; 
                     if (isTriggerEnd) {
                       long timeMicros = this.intervalManager.getTimeForTriggerEnd((long) intervalMicros);
                        
                       int eventConstant = 3;
                       //boolean isCycleStart; 
                       isCycleEnd = isCycleStart = false;
                       long newTimeMicros = this.timeManager.getTimeVal(atts, 
                         timeMicros);
                       if (newTimeMicros != timeMicros) {
                         this.intervalManager.lastTriggerEnd = (timeMicros = newTimeMicros);
                       }
                     } else {
                       isCycleEnd = type.equals("cycle end");
                       if (isCycleEnd) {
                         long timeMicros = this.intervalManager
                           .getTimeForCycleEnd((long) intervalMicros);
                         int eventConstant = 5;
                          isCycleStart = false;
                         long newTimeMicros = this.timeManager.getTimeVal(atts, 
                           timeMicros);
                         if (newTimeMicros != timeMicros) {
                           this.intervalManager.lastCycleEnd = (timeMicros = newTimeMicros);
                         }
                       } else {
                         isCycleStart = type.equals("cycle start");
                         if (isCycleStart) {
                           long timeMicros = this.intervalManager
                             .getTimeForCycleStart((long) intervalMicros);
                           int eventConstant = 4;
                           long newTimeMicros = this.timeManager.getTimeVal(atts, 
                             timeMicros);
                           if (newTimeMicros != timeMicros) {
                             this.intervalManager.lastCycleStart = (timeMicros = newTimeMicros);
                           }
                         } else if (type.equals("trigger start")) {
                           this.isGoodData = true;
                           long timeMicros = this.intervalManager
                             .getTimeForTriggerStart((long) intervalMicros);
                           int eventConstant = 12;
                           long newTimeMicros = this.timeManager.getTimeVal(atts, 
                             timeMicros);
                           if (newTimeMicros != timeMicros)
                             this.intervalManager.lastTriggerStart = (timeMicros = newTimeMicros);
                         } else {
                           return;
                         }
                       }
                     }
                     int eventConstant = 0;
                     long timeMicros = 0;
                     double timeMillis = timeMicros / 1000.0D;
                     this.xAxis.setX(timeMillis);
                     
                     if (isTriggerEnd) {
                       addDataPoint(this.triggerDurations, intervalMillis, 
                         this.currentComment);
                     } else if (isCycleEnd)
                     {
                       if (timeMicros < this.intervalManager.lastHeartbeat) {
                         timeMicros = this.intervalManager.lastHeartbeat;
                         timeMillis = timeMicros / 1000.0D;
                         this.intervalManager.lastCycleEnd = this.intervalManager.lastHeartbeat;
                         this.xAxis.setX(timeMillis);
                       }
                       
                       this.commonData.lastGCCycleMillis = timeMillis;
                       long freebytes = CommonData.convertPositiveInteger(atts
                         .getValue("heapfreebytes"));
                       if (freebytes >= 0L) {
                         this.commonData.freeHeap.addDataPoint(freebytes, 
                           this.currentComment);
                       }
                       addDataPoint(this.cycleDurations, intervalMillis, this.currentComment);
                       int cycleQuantaCount = this.heartbeatParser.cycleQuantaCount;
                       this.heartbeatParser.cycleQuantaCount = 0;
                       addDataPoint(this.quantaPerCycle, cycleQuantaCount, 
                         this.currentComment);
                       this.cycleCount += 1L;
                     } else if (isCycleStart) {
                       long freebytes = CommonData.convertPositiveInteger(atts
                         .getValue("heapfreebytes"));
                       if (freebytes >= 0L) {
                         this.commonData.freeHeap.addDataPoint(freebytes, 
                           this.currentComment);
                       }
                       double lastGCCycleMillis = Math.max(this.commonData
                         .getInitialTimeMicros() / 
                         1000.0D, this.commonData.lastGCCycleMillis);
                       addDataPoint(this.commonData.cycleIntervals, timeMillis - 
                         lastGCCycleMillis, this.currentComment);
                     }
                     this.eventHandler.handleGCActivity(type, eventConstant, id, 
                       this.currentComment);
                     this.eventHandler.complete();
                     this.gcNumberConverter.addPoint(this.xAxis.getSequenceUID(), 
                       ++this.commonData.currentGCNumber);
                   }
                   return;
                 }
                 if (name.equals("event")) {
                   initialize();
                   String details = atts.getValue("details");
                   if (details == null) {
                     return;
                   }
                   int eventConstant;
                   if (details.equals("utilization tracker overflow")) {
                     eventConstant = 6; } else {  
                     if (details.equals("non-monotonic time acknowledged")) {
                       eventConstant = 7; } else {  
                       if (details.equals("out of memory"))
                         eventConstant = 9; else return;
                     }
                   }
                   //int eventConstant;
                   double timeMillis = this.timeManager.getTimeVal(atts) / 
                     1000.0D;
                   this.xAxis.setX(timeMillis);
                   this.currentComment = COMBINED_COMMENT
                     .format(new Object[] { name, details });
                   this.eventHandler.handleCurrentEvent(details, eventConstant, (long)timeMillis, this.currentComment);
                   return;
                 }
                 if (name.equals("verbosegc")) {
                   initialize();
                   
                   this.restartCount += 1;
                   
                   if (this.xAxis.getX() >= 0.0D) {
                     addDataPoint(this.restartTuple, 1.0D, "");
                     initializeTime(this.restartCount - 1);
                   }
                   
                   workOutVersion(atts);
                   return;
                 }
                 if (name.equals("initialized")) {
                   initialize();
                   this.currentParser = this.attributeParser;
                   return;
                 }
                 if (name.equals("file")) {
                   initialiseGeneralSourceData(this.source, this.properties);
                   this.initialized = true;
                   return;
                 }
               }
               
               private void initialize() {
                 if (this.initialized) {
                   return;
                 }
                 this.initialized = true;
                 initialiseGeneralSourceData(this.source, this.properties);
               }
               
               public void endElement(String uri, String localName, String name) {
                 if (this.currentParser != null) {
                   if (this.currentParser.endElement(uri, localName, name, this.currentComment)) {
                     return;
                   }
                   this.currentParser = null;
                 }
                 if (name.equals("file")) {
                   writeOutSourceData();
                 }
               }
               
               private void writeOutSourceData() {
                 if (this.isGoodData) {
                   addData(this.attributeParser.attributes);
                   addData(this.eventHandler.gcActivity);
                   addData(this.eventHandler.eventIds);
                   addData(this.triggerDurations);
                   if (this.cycleCount > 0L) {
                     addData(this.cycleDurations);
                     addData(this.quantaPerCycle);
                     addData(this.commonData.cycleIntervals);
                   }
                   addData(this.heartbeatParser.quantaPerHeartbeat);
                   HeartBeatSummaryParser heartbeatSummaryParser = this.heartbeatParser.summaryParser;
                   addData(heartbeatSummaryParser.minPause);
                   addData(heartbeatSummaryParser.maxPause);
                   addData(heartbeatSummaryParser.meanPause);
                   
                   String pauseUnits = heartbeatSummaryParser.meanPause
                     .getYAxis().getAxis().getBaseUnitName();
                   StructuredDataBuilder quantumPauseSummary = factory
                     .createStructuredData(
                     "RealtimeLabels.quantum.pause.summary", 
                     
                     Messages.getString("RealtimeLabels.quantum.pause.summary"));
                   
                   quantumPauseSummary.put(MessageFormat.format(
                     Messages.getString("RealtimeLabels.minimum.quantum.pause.summary"), 
                     new Object[] { pauseUnits }), 
                     Double.valueOf(heartbeatSummaryParser.minPause.getMinY(pauseUnits)));
                   
                   quantumPauseSummary.put(MessageFormat.format(
                     Messages.getString("RealtimeLabels.maximum.quantum.pause.summary"), 
                     new Object[] { pauseUnits }), 
                     Double.valueOf(heartbeatSummaryParser.maxPause.getMaxY(pauseUnits)));
                   
                   quantumPauseSummary.put(MessageFormat.format(
                     Messages.getString("RealtimeLabels.mean.quantum.pause.summary"), 
                     new Object[] { pauseUnits }), new Double(
                     heartbeatSummaryParser.meanPause.getMeanY(pauseUnits)));
                   
                   long synchCount = this.synchGCParser.synchGCCount;
                   quantumPauseSummary.put(
                     Messages.getString("RealtimeLabels.synch.gc.count"), Long.valueOf(synchCount));
                   if (this.cycleCount > 0L) {
                     quantumPauseSummary.put(
                       Messages.getString("RealtimeLabels.concurrent.gc.count"), 
                       Long.valueOf(this.cycleCount));
                   }
                   addData(quantumPauseSummary);
                   addData(heartbeatSummaryParser.minXAccess);
                   addData(heartbeatSummaryParser.maxXAccess);
                   addData(heartbeatSummaryParser.meanXAccess);
                   if (!this.commonData.minpriority.isEmpty()) {
                     addData(this.commonData.minpriority);
                   }
                   if (!this.commonData.maxpriority.isEmpty()) {
                     addData(this.commonData.maxpriority);
                   }
                   addData(this.commonData.minFreeHeap);
                   addData(this.commonData.maxFreeHeap);
                   addData(this.commonData.meanFreeHeap);
                   if ((this.cycleCount > 0L) || (this.hasSynchGC)) {
                     addData(this.commonData.freeHeap);
                   }
                   if ((heartbeatSummaryParser.hasImmortal) || (this.synchGCParser.hasImmortal)) {
                     addData(this.commonData.minFreeImmortal);
                     addData(this.commonData.maxFreeImmortal);
                     addData(this.commonData.meanFreeImmortal);
                   } else {
                     if (!this.commonData.classloadersUnloaded.isEmpty()) {
                       addData(this.commonData.classloadersUnloaded);
                     }
                     if (!this.commonData.classesUnloaded.isEmpty()) {
                       addData(this.commonData.classesUnloaded);
                     }
                   }
                   if (!this.commonData.objectsQueuedForFinalization.isEmpty()) {
                     addData(this.commonData.objectsQueuedForFinalization);
                   }
                   if (!this.commonData.softRefsCleared.isEmpty()) {
                     addData(this.commonData.softRefsCleared);
                   }
                   if (!this.commonData.weakRefsCleared.isEmpty()) {
                     addData(this.commonData.weakRefsCleared);
                   }
                   if (!this.commonData.phantomRefsCleared.isEmpty()) {
                     addData(this.commonData.phantomRefsCleared);
                   }
                   if (!this.synchGCParser.durations.isEmpty()) {
                     addData(this.synchGCParser.durations);
                   }
                   addData(this.eventHandler.events);
                   if (!this.restartTuple.isEmpty()) {
                     addData(this.restartTuple);
                   }
                   recordVersion();
                 }
               }
               
               protected void initialiseSpecificSourceData(OutputProperties properties) {
                 YDataAxis activityAxis = VGCAxes.prepareEventAxis(properties);
                 YDataAxis numberAxis = 
                   VGCAxes.prepareDiscreteNumberAxis(properties);
                 YDataAxis timeAxis = VGCAxes.prepareTimeAxis(properties);
                 AxisPair activityPair = factory.createAxisPair(this.xAxis, activityAxis);
                 AxisPair heapAxisPair = factory.createAxisPair(this.xAxis, this.heapAxis);
                 AxisPair timePair = factory.createAxisPair(this.xAxis, timeAxis);
                 AxisPair numberPair = factory.createAxisPair(this.xAxis, 
                   numberAxis);
                 
                 this.triggerDurations = factory
                 
                   .createTupleData("RealtimeLabels.trigger.durations", Messages.getString("RealtimeLabels.trigger.durations"), timePair);
                 this.cycleDurations = factory
                 
                   .createTupleData("RealtimeLabels.cycle.durations", Messages.getString("RealtimeLabels.cycle.durations"), timePair);
                 this.quantaPerCycle = factory
                 
                   .createTupleData("RealtimeLabels.quanta.per.cycle", Messages.getString("RealtimeLabels.quanta.per.cycle"), numberPair);
                 
                 TupleMetaData tiggerDurationsMetaData = new TupleMetaData(
                   TupleMetaData.TableType.ARITHMETIC, new TupleMetaData.TableField[] { TupleMetaData.TableField.MEAN, 
                   TupleMetaData.TableField.MIN, TupleMetaData.TableField.MAX });
                 TupleMetaData cycleDurationsMetaData = new TupleMetaData(
                   TupleMetaData.TableType.ARITHMETIC, new TupleMetaData.TableField[] { TupleMetaData.TableField.MEAN, 
                   TupleMetaData.TableField.MIN, TupleMetaData.TableField.MAX, TupleMetaData.TableField.TOTAL });
                 TupleMetaData quantaPerCycleMetaData = new TupleMetaData(
                   TupleMetaData.TableType.ARITHMETIC, new TupleMetaData.TableField[] { TupleMetaData.TableField.MEAN, 
                   TupleMetaData.TableField.MIN, TupleMetaData.TableField.MAX });
                 this.triggerDurations.setTupleMetaData(tiggerDurationsMetaData);
                 this.cycleDurations.setTupleMetaData(cycleDurationsMetaData);
                 this.quantaPerCycle.setTupleMetaData(quantaPerCycleMetaData);
                 
                 this.eventHandler = new GCEventHandler(factory, this.eventConverter, 
                   activityPair, numberPair);
                 this.commonData = new CommonData(this.xAxis, this.eventHandler, this.gcNumberConverter, 
                   factory, heapAxisPair, numberPair, timePair);
                 initializeTime(0);
                 this.heartbeatParser = new HeartBeatParser(this.commonData, factory, timePair, 
                   numberPair, timePair, activityPair, 
                   this.interpolateTimestamps);
                 this.synchGCParser = new SynchGCParser(this.commonData, this.filterSystemGCs, factory, 
                   timePair);
                 this.attributeParser = new AttributeParser(this.commonData, factory);
               }
               
               void initializeTime(int restart) {
                 this.intervalManager = new IntervalManager(this.commonData);
                 this.timeManager = new TimeManager(this.commonData);
               }
             }


